package com.lyn.solitude_plugin_host.builder;

import android.app.Application;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;

import androidx.annotation.NonNull;

import com.lyn.solitude_plugin_api.file.Folder;
import com.lyn.solitude_plugin_api.file.FolderFactory;

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import dalvik.system.DexClassLoader;

/**
 * @author longyn 2024/4/21
 * @version 1.0.0
 */
public class ImpBuilderHelper {

    private final static String TAG = "ImpBuilderHelper";

    private final Application application;

    public ImpBuilderHelper(Application application) {
        this.application = application;
    }

    /**
     * 获取包管理器
     */
    public PackageManager getPackageManager() {
        return this.application.getPackageManager();
    }


    /**
     * 获取插件ApplicationInfo
     *
     * @param pluginFilePath 插件文件路径
     * @return ApplicationInfo
     */
    public ApplicationInfo getPluginApplicationInfo(String pluginFilePath) {
        try {
            PackageManager packageManager = this.application.getPackageManager();
            PackageInfo packageInfo = packageManager.getPackageArchiveInfo(pluginFilePath,
                    PackageManager.GET_ACTIVITIES);
            if (packageInfo != null) {
                packageInfo.applicationInfo.sourceDir = pluginFilePath;
                packageInfo.applicationInfo.publicSourceDir = pluginFilePath;
                return packageInfo.applicationInfo;
            }
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取插件ApplicationInfo
     *
     * @param pluginFilePath 插件文件路径
     * @param flags          – Additional option flags to modify the data returned.
     * @return ApplicationInfo
     */
    public ApplicationInfo getPluginApplicationInfo(String pluginFilePath, int flags) {
        try {
            PackageManager packageManager = this.application.getPackageManager();
            PackageInfo packageInfo = packageManager.getPackageArchiveInfo(pluginFilePath, flags);
            if (packageInfo != null) {
                packageInfo.applicationInfo.sourceDir = pluginFilePath;
                packageInfo.applicationInfo.publicSourceDir = pluginFilePath;
                packageInfo.applicationInfo.sharedLibraryFiles = application.getApplicationInfo().sharedLibraryFiles;
                return packageInfo.applicationInfo;
            }
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取插件mateData
     *
     * @param pluginFilePath 插件路径
     * @return bundle
     */
    public Bundle getPluginBundle(String pluginFilePath) {
        try {
            PackageManager packageManager = this.application.getPackageManager();
            PackageInfo packageInfo = packageManager.getPackageArchiveInfo(pluginFilePath,
                    PackageManager.GET_META_DATA);
            if (packageInfo != null) {
                packageInfo.applicationInfo.sourceDir = pluginFilePath;
                packageInfo.applicationInfo.publicSourceDir = pluginFilePath;
                return packageInfo.applicationInfo.metaData;
            }
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取插件 Resources
     *
     * @param pluginApplicationInfo 插件ApplicationInfo
     * @return Resources
     */
    public Resources getPluginResources(ApplicationInfo pluginApplicationInfo) {
        try {
            return getPackageManager().getResourcesForApplication(pluginApplicationInfo);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取插件logo
     *
     * @param pluginApplicationInfo 插件ApplicationInfo
     * @return Drawable
     */
    public Drawable getPluginLogo(ApplicationInfo pluginApplicationInfo) {
        return getPackageManager().getApplicationIcon(pluginApplicationInfo);
    }

    /**
     * 获取插件名称
     *
     * @param pluginApplicationInfo 插件ApplicationInfo
     * @return String
     */
    public String getPluginName(ApplicationInfo pluginApplicationInfo) {
        return (String) getPackageManager().getApplicationLabel(pluginApplicationInfo);
    }

    /**
     * 获取插件classLoader
     *
     * @param pluginFilePath      插件文件路径
     * @param pluginOptimizedPath 插件优化路径
     * @param pluginSoPath        插件so路径
     * @return ClassLoader
     */
    public ClassLoader getPluginClassLoader(String pluginFilePath, String pluginOptimizedPath, String pluginSoPath) {
        return new DexClassLoader(pluginFilePath,
                pluginOptimizedPath,
                pluginSoPath, application.getClassLoader());
    }

    /**
     * 获取插件className
     *
     * @param pluginFilePath 插件文件路径
     */
    public String getPluginClassName(String pluginFilePath) {
        Bundle pluginMateData = getPluginBundle(pluginFilePath);
        if (pluginMateData != null) {
            return pluginMateData.getString("pluginClassName", "");
        }
        return "";
    }

    /**
     * 获取插件版本号
     *
     * @param pluginFilePath 插件文件路径
     * @return 版本号
     */
    public int getPluginVersion(String pluginFilePath) {
        Bundle pluginBundle = getPluginBundle(pluginFilePath);
        if (pluginBundle != null) {
            return pluginBundle.getInt("pluginVersion", 1);
        }
        return -1;
    }

    /**
     * 提取插件
     *
     * @param pluginFilePath 插件文件路径
     * @return so文件路径
     */
    public String extractPluginSo(String pluginFilePath, String soFolderPath, String soFolderName) {
        try {
            File file = new File(pluginFilePath);
            String cpuAbi = getCPUAbi();
            Log.d(TAG, "cpuAbi:" + cpuAbi);
            ZipFile zipFile = new ZipFile(file);
            Enumeration<? extends ZipEntry> entries = zipFile.entries();
            FolderFactory.create(soFolderPath
                    + "/" + soFolderName, soFolderName);
            Folder soFolder = FolderFactory.getFolder(soFolderName);
            if (soFolder == null) {
                Log.d(TAG, "extractPluginSo soFolder == null");
                return "";
            }
            while (entries.hasMoreElements()) {
                ZipEntry zipEntry = entries.nextElement();
                String zipEntryName = zipEntry.getName();
                if (!zipEntryName.startsWith("lib")) {
                    continue;
                }
                Log.d(TAG, "zipEntryName:" + zipEntryName);
                if (!zipEntryName.contains(cpuAbi)) {
                    Log.d(TAG, "!zipEntryName.contains(cpuAbi)");
                    continue;
                }
                if (!zipEntryName.endsWith(".so")) {
                    Log.d(TAG, "!zipEntryName.endsWith(\".so\")");
                    continue;
                }
                String[] split = zipEntryName.split("/");
                String soFileName = split[split.length - 1];
                if (TextUtils.isEmpty(soFileName)) {
                    Log.d(TAG, "TextUtils.isEmpty(soFileName)");
                    continue;
                }
                Log.d(TAG, "soFileName:" + soFileName);
                InputStream inputStream = zipFile.getInputStream(zipEntry);
                soFolder.saveFile(inputStream, soFileName);
            }
            return soFolder.getPath();
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return "null";
    }

    /**
     * 获取不带扩展名的文件名
     */
    private String getFileNameWithoutExtension(File file) {
        return file.getName().substring(0, file.getName().lastIndexOf("."));
    }

    /**
     * 获取cpu架构
     *
     * @return cpu架构
     */
    private String getCPUAbi() {
        return execShell("getprop ro.product.cpu.abi");
    }

    /**
     * 执行adb命令
     *
     * @param cmd 命令
     * @return 结果
     */
    private String execShell(@NonNull String cmd) {
        StringBuilder sb = new StringBuilder();
        try {
            Runtime runtime = Runtime.getRuntime();
            Process process = runtime.exec(cmd);
            InputStream inputStream = process.getInputStream();
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
            process.waitFor();
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                sb.append(line).append("\n");
            }
            inputStream.close();
            bufferedReader.close();
            String string = sb.toString();
            if (!TextUtils.isEmpty(string)) {
                if (string.endsWith("\n")) {
                    return string.substring(0, string.length() - 1);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

}
